/*
 * @Author: 0x9DEFA478
 * @Date: 2023-05-24 20:50:27
 * @LastEditTime: 2025-10-18 00:09:59
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * 
 */
#include <thread>
#include <chrono>
#include <unistd.h>
#include <string.h>
#include "H_Pointer.hpp"
#include "Utility/H_String.h"
#include "Utility/H_String.hpp"
#include "Container/H_Stack.hpp"
#include "Tree/H_Tree_AVL.hpp"
#include "SystemUtility/C_LocalUTF8.hpp"
#include "SystemUtility/C_ArgumentDecode.hpp"
#include "SystemUtility/C_iostream.hpp"
#include "SystemUtility/C_Printf.h"
#include "SystemAPI/Windows/Error.hpp"
#include "HMakeDecode.hpp"
#include "HMakeTargetTask_C_CPP.hpp"
#include "HMakeTargetTask_Command.hpp"
#include "HMakeDependencyItem_Instance.hpp"
#include "HMakeLog.hpp"
#include "SystemUtility/C_VirtualTerminal_Macro.h"
#ifdef __linux__
#include <linux/limits.h>
#endif

#ifdef _WIN32
#include "windows.h"
#endif




std::string durationToHMSMString(std::chrono::milliseconds duration){
  auto count=duration.count();

  auto s=count/1000;
  auto m=s/60;
  auto h=m/60;

  count%=1000;
  s%=60;
  m%=60;

  return H::String::Format("%d:%02d:%02d.%03d",(int)h,(int)m,(int)s,(int)count);
}




#define LOG_RED                                                   "\e[" C_VT_F_Red "m"
#define LOG_YELLOW                                                "\e[" C_VT_F_Yellow "m"
#define LOG_CYAN                                                  "\e[" C_VT_F_Cyan "m"
#define LOG_GREEN                                                 "\e[" C_VT_F_Green "m"
#define LOG_B_GREEN                                               "\e[" C_VT_B_Green "m"
#define LOG_RESET                                                 "\e[0m"
#define LOG_ERROR_TEXT                                            LOG_RED "错误" LOG_RESET
#define LOG_TARGET                                                LOG_CYAN



//================================================================
//命令行参数处理

static const char* Version="0.0.2";

static H::ArgumentDecode::Option arg_Option_help("--help");
static H::ArgumentDecode::Option arg_Option_version("--version");
static H::ArgumentDecode::Option arg_Option_hmk("--hmk");
static H::ArgumentDecode::Option arg_Option_target("--target");
static H::ArgumentDecode::Option arg_Option_shell("--shell");
static H::ArgumentDecode::Option arg_Option_j("-j");
static H::ArgumentDecode::Option arg_Option_print("--print");
static H::ArgumentDecode argumentDecode;

static void OptionInit(){
  argumentDecode.AddOption(&arg_Option_help);
  argumentDecode.AddOption(&arg_Option_version);
  argumentDecode.AddOption(&arg_Option_hmk);
  argumentDecode.AddOption(&arg_Option_target);
  argumentDecode.AddOption(&arg_Option_shell);
  argumentDecode.AddOption(&arg_Option_j);
  argumentDecode.AddOption(&arg_Option_print);
}

static void help(){
  H::cout<<"\t--help    打开本菜单"<<std::endl;
  H::cout<<"\t--version 获取版本号"<<std::endl;
  H::cout<<"\t--hmk     设置hmk文件          用法: --hmk=<hmk路径>"<<std::endl;
  H::cout<<"\t--target  设置目标             用法: --target=<目标>"<<std::endl;
  H::cout<<"\t--shell   设置执行脚本的shell  用法: --shell=<shell名>"<<std::endl;
  H::cout<<"\t-j        设置并发的任务数     用法: -j=<任务数>"<<std::endl;
  H::cout<<"\t--print   设置要额外输出的信息 用法: --print=TargetValue,BuildArgs,SkipLog"<<std::endl;
}
//================================================================


//================================================================
//任务链构造

struct MakeContext{
  std::string target;
  std::string cwd;
  std::string shell;
  HMake::TargetTask::AttributeMask TargetTask_Attribute;
  HMake::DependencyChain::Item::Pointer hmkDependency;
  HMake::DependencyItem_Directory::Collection::Pointer DirectoryTaskCollection;
  HMake::Log::Pointer log;
};

static auto taskCreatorMap=H::Tree::AVL<std::string,std::function<
    HMake::TargetTask::Pointer (MakeContext&,const HMake::TargetConfig::Pointer)
  >>{
  {"GCC",[](MakeContext& Context,const HMake::TargetConfig::Pointer targetConfig){
    return HMake::TargetTask_GCC::New(targetConfig,Context.hmkDependency,Context.cwd,Context.shell,Context.DirectoryTaskCollection,Context.log,Context.TargetTask_Attribute);
  }},
  {"Shell",[](MakeContext& Context,const HMake::TargetConfig::Pointer targetConfig){
    return HMake::TargetTask_Command::New(targetConfig,Context.hmkDependency,Context.cwd,Context.shell,Context.DirectoryTaskCollection,Context.log,Context.TargetTask_Attribute);
  }}
};

static HMake::TargetTask::Pointer MakeTagetTask(MakeContext& Context,const HMake::TargetConfig::Pointer& config){
  auto value=config->FindValue("HMake.Target.BuildTool.Type");
  if((value==nullptr)||(!value->Valid())){
    throw std::runtime_error("目标 " LOG_TARGET+config->Name()+LOG_RESET " 无法获取构建工具类型");
  }

  auto taskCreator=taskCreatorMap.Find(value->ValueArray()[0]);
  if(taskCreator==taskCreatorMap.end()){
    throw std::runtime_error("目标 " LOG_TARGET+config->Name()+LOG_RESET " 具有不支持的构建工具类型 " LOG_RED+value->ValueArray()[0]+LOG_RESET);
  }

  HMake::TargetTask::Pointer task;
  try{
    task=taskCreator->Data()(Context,config);
  }catch(const std::exception& e){
    throw std::runtime_error("构造目标 " LOG_TARGET+config->Name()+LOG_RESET " 的任务链时失败:"+e.what());
  }

  return task;
}

static HMake::DependencyChain::Item::Pointer MakeTask(MakeContext& Context,H::Tree::AVL<std::string,HMake::TargetConfig::Pointer> ConfigMap,std::list<HMake::TargetTask::Pointer>& targetList){
  
  struct StackItem{
    bool IsFindRoot;
    std::string TargetName;
    HMake::DependencyChain::Item::Pointer TaskRoot;
    std::list<H::Pointer<std::string>> DependencyName;

    explicit StackItem(const std::string& TargetName):IsFindRoot(false),TargetName(TargetName){}
  };

  H::Stack<StackItem> stack;

  StackItem currentStatus(Context.target);

  for(;;){

    if(!currentStatus.IsFindRoot){
      auto Confing=ConfigMap.Find(currentStatus.TargetName);

      if(Confing==ConfigMap.end()){
        throw std::runtime_error("目标 " LOG_TARGET+currentStatus.TargetName+LOG_RESET " 无法找到hmk配置");
      }

      auto task=MakeTagetTask(Context,Confing->Data());

      targetList.emplace_back(task);
      currentStatus.TaskRoot=task->MakeTask();

      auto val=Confing->Data()->FindValue("HMake.Target.Dependency");

      if((val!=nullptr)&&(val->Valid())&&(val->ValueArray().Length()>0)){
        for(auto& Item:val->ValueArray()){
          for(auto& name:currentStatus.DependencyName){
            if(Item==*name){
              throw std::runtime_error("目标 " LOG_TARGET+currentStatus.TargetName+LOG_RESET " 重复的依赖:"+Item);
            }
          }
          currentStatus.DependencyName.emplace_back(H::Pointer<std::string>::New(Item));
        }
      }

      currentStatus.IsFindRoot=true;
    }

    if(!currentStatus.DependencyName.empty()){
      auto name=currentStatus.DependencyName.front();
      currentStatus.DependencyName.pop_front();

      stack.Push(currentStatus);
      currentStatus=StackItem(*name);
      continue;
    }

    if(stack.Empty()){
      break;
    }
    HMake::DependencyChain::AddDependency(stack.Top().TaskRoot,currentStatus.TaskRoot);
    currentStatus=stack.Top();
    stack.Pop();
  }

  return currentStatus.TaskRoot;
}
//================================================================


int main(int argc,char* argv[]){

#ifdef _WIN32
  do{
    HANDLE consoleHandle;
    DWORD Mode;

    consoleHandle=GetStdHandle(STD_OUTPUT_HANDLE);
    if(consoleHandle==INVALID_HANDLE_VALUE){
      C_Printf("无法获取标准输出句柄:%s 日志输出可能会出现异常\n",SystemAPI::Windows::GetErrorString().c_str());
      break;
    }

    if(!GetConsoleMode(consoleHandle,&Mode)){
      C_Printf("无法获取控制台模式:%s 日志输出可能会出现异常\n",SystemAPI::Windows::GetErrorString().c_str());
      break;
    }

    if(!SetConsoleMode(consoleHandle,Mode|ENABLE_VIRTUAL_TERMINAL_PROCESSING)){
      C_Printf("无法设置控制台模式:%s 日志输出可能会出现异常\n",SystemAPI::Windows::GetErrorString().c_str());
      break;
    }

  }while(false);
#endif


  MakeContext Context;
  Context.DirectoryTaskCollection=HMake::DependencyItem_Directory::Collection::Pointer::New();

  Context.TargetTask_Attribute=HMake::TargetTask::AttributeMask::None;

#ifdef _WIN32
  Context.shell="PowerShell";//Windows下默认使用PowerShell
#else
  Context.shell="bash";//默认使用bash
#endif
  int MaxJob=1;
  bool IsPrintTargetValue=false;


  {
    auto buffer=H::Pointer<char>::Array(PATH_MAX);

    auto path=getcwd(buffer,PATH_MAX);
    if(path==nullptr){
      return 1;
    }
    Context.cwd=std::string(path,strnlen(path,PATH_MAX));
  }

  auto argumentValue=H::Pointer<const char*>::Array(argc);
  auto argumentValueString=H::Pointer<std::string>::Array(argc);

  for(int i=0;i<argc;i++){
    argumentValueString[i]=H::Local_To_UTF8(argv[i]);
    argumentValue[i]=argumentValueString[i].c_str();
  }

  OptionInit();

  try{
    argumentDecode.Decode(argc,argumentValue);
  }catch(const std::invalid_argument& e){
    H::cout<<"参数" LOG_ERROR_TEXT ": "<<e.what()<<std::endl;
    return 1;
  }catch(const std::exception& e){
    H::cout<<"非预期的" LOG_ERROR_TEXT ": "<<e.what()<<std::endl;
    return 1;
  }

  if(arg_Option_help){
    help();
    return 0;
  }

  if(arg_Option_version){
    H::cout<<"HMake 版本: "<<Version<<std::endl;
    H::cout<<"  by 0x9DEFA478"<<std::endl;
    return 0;
  }

  std::string hmk="./HMake.hmk";
  if(arg_Option_hmk){
    if((!arg_Option_hmk.ValueValid())||(arg_Option_hmk.GetValue().length()<1)){
      H::cout<<LOG_RED "未能设置hmk文件" LOG_RESET ", 需要使用 --hmk=<hmk路径>"<<std::endl;
      return 1;
    }
    hmk=arg_Option_hmk.GetValue();
  }

  if((!arg_Option_target)||(!arg_Option_target.ValueValid())||(arg_Option_target.GetValue().length()<1)){
    H::cout<<LOG_RED "未能设置目标" LOG_RESET ", 需要使用 --target=<目标>"<<std::endl;
    return 1;
  }
  Context.target=arg_Option_target.GetValue();

  if(arg_Option_shell){
    if((!arg_Option_shell.ValueValid())||(arg_Option_shell.GetValue().length()<1)){
      H::cout<<LOG_RED "未能设置要使用的shell" LOG_RESET ", 需要使用 --shell=<shell名>"<<std::endl;
      return 1;
    }
    Context.shell=arg_Option_shell.GetValue();
  }

  if(arg_Option_j){
    if((!arg_Option_j.ValueValid())||(arg_Option_j.GetValue().length()<1)){
      H::cout<<LOG_RED "未能设置任务数" LOG_RESET ", 需要使用 -j=<任务数>"<<std::endl;
      return 1;
    }
    try{
      MaxJob=std::stoi(arg_Option_j.GetValue());
    }catch(const std::exception& e){
      H::cout<<LOG_RED "未能设置任务数" LOG_RESET ", "<<e.what()<<std::endl;
      return 1;
    }
    if(MaxJob<1){
      H::cout<<LOG_RED "未能设置任务数" LOG_RESET ", 错误的任务数:"<<MaxJob<<std::endl;
      return 1;
    }
  }

  if(arg_Option_print&&arg_Option_print.ValueValid()){
    const char* str=arg_Option_print.GetValue().c_str();
    
    for(;;){
      H::size len;
      bool IsEnd=false;
      
      len=H_StringFindFirstChar(str,',');

      if(len<0){
        if(str[0]=='\0'){
          break;
        }
        len=H_StringLength(str);
        IsEnd=true;
      }

      if(len>0){
        auto setting=std::string(str,len);
        if(setting=="TargetValue"){
          IsPrintTargetValue=true;
        }else if(setting=="BuildArgs"){
          Context.TargetTask_Attribute|=HMake::TargetTask::AttributeMask::IsPrintArg;
        }else if(setting=="SkipLog"){
          Context.TargetTask_Attribute|=HMake::TargetTask::AttributeMask::IsPrintSkip;
        }else{
          H::cout<<LOG_RED "不识别的设置" LOG_RESET ": "<<setting<<std::endl;
          return 1;
        }
      }
      if(IsEnd){
        break;
      }
      str+=len+1;
    }
  }



  //用于语法测试 输出hmk运算关系
  // extern void Debug_Call(const std::string& path);
  // Debug_Call(hmk);

  HMake::Decoder decoder(Context.cwd,Context.target);
  
  H::cout<<LOG_YELLOW "===================================================================" LOG_RESET<<std::endl;
  H::cout<<LOG_B_GREEN "分析HMK" LOG_RESET<<std::endl;
  try{

    auto startTP=std::chrono::system_clock::now();

    decoder.Load(hmk);

    auto configArray=decoder.GetTargetConfigCollection();

    Context.log=HMake::Log::New(H::cout);
    Context.hmkDependency=HMake::DependencyItem_Input::New(hmk);
    Context.hmkDependency->UpdateTargetStatus();
    std::list<HMake::TargetTask::Pointer> targetList;
    auto Task=MakeTask(Context,configArray,targetList);

    auto hmkLoadDoneTP=std::chrono::system_clock::now();
    H::cout<<"  解析耗时: "<<durationToHMSMString(std::chrono::duration_cast<std::chrono::milliseconds>(hmkLoadDoneTP-startTP))<<std::endl;

    if(IsPrintTargetValue){
      for(auto& Item:configArray){
        H::cout<<"Config " LOG_CYAN+Item.Key()+LOG_RESET ":"<<std::endl;
        auto str=Item.Data()->ToString();
        H::cout<<str;
      }
      H::cout<<std::endl;
    }

    H::cout<<LOG_B_GREEN "进行构建前任务" LOG_RESET<<std::endl;
    auto prebuildStartTP=std::chrono::system_clock::now();
    for(auto& Item:targetList){
      H::cout<<"PreBuild " LOG_TARGET<<Item->Name()<<LOG_RESET<<std::endl;
      Item->PreBuild();
    }
    auto prebuildStopTP=std::chrono::system_clock::now();
    H::cout<<"  构建前任务耗时: "<<durationToHMSMString(std::chrono::duration_cast<std::chrono::milliseconds>(prebuildStopTP-prebuildStartTP))<<std::endl;

    H::cout<<LOG_B_GREEN "开始构建" LOG_RESET<<std::endl;

    Context.log->ResetCount(Task->GetDependencyCount()+1);

    Context.log->Start();
    auto buildStartTP=std::chrono::system_clock::now();
    auto taskResult=HMake::DependencyChain::Run(Task,MaxJob);
    auto buildStopTP=std::chrono::system_clock::now();
    Context.log->Stop();
    H::cout<<std::endl;
    if(Context.log->UpdateCount()==0){
      H::cout<<LOG_B_GREEN "没有依赖更新" LOG_RESET<<std::endl;
    }
    H::cout<<"  更新 "<<Context.log->UpdateCount()<<" 个, 跳过 "<<Context.log->SkipCount()<<" 个"<<std::endl;
    H::cout<<"  构建耗时: "<<durationToHMSMString(std::chrono::duration_cast<std::chrono::milliseconds>(buildStopTP-buildStartTP))<<std::endl;

    if(taskResult!=0){
      H::cout<<LOG_RED "执行构建任务过程中发生错误" LOG_RESET " 返回值:"<<taskResult<<std::endl;
      return taskResult;
    }

    auto postbuildStopTP=std::chrono::system_clock::now();
    H::cout<<"  总耗时: "<<durationToHMSMString(std::chrono::duration_cast<std::chrono::milliseconds>(postbuildStopTP-startTP))<<std::endl;

    H::cout<<LOG_YELLOW "完成" LOG_RESET<<std::endl;
    H::cout<<LOG_YELLOW "===================================================================" LOG_RESET<<std::endl;

  }catch(const std::exception& e){
    H::cout<<LOG_RED "发生错误:" LOG_RESET<<std::endl<<e.what()<<std::endl;
    H::cout<<LOG_RED "===================================================================" LOG_RESET<<std::endl;
    return 1;
  }

  return 0;
}




